﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;

namespace System.ApplicationModel
{
    public partial class Entity : IChangeTracking
    {
#if (!SILVERLIGHT)
        [NonSerialized]
#endif
        private bool _isChanged;

        #region IChangeTracking Implementation
        /// <summary>
        /// Resets the object’s state to unchanged by accepting the modifications.
        /// </summary>
        public void AcceptChanges()
        {
            if (object.ReferenceEquals(this._backup, null))
                return;


            foreach (KeyValuePair<string, dynamic> item in this._backup)
            {
#if SILVERLIGHT
                PropertyInfo property = this.GetType().GetProperty(item.Key);
                object[] attributes = property.GetCustomAttributes(typeof(EditableAttribute), true);

                EditableAttribute attribute = null;
                if (attributes.Count() == 1)
                {
                    attribute = attributes[0] as EditableAttribute;
                }

                object propValue = property.GetValue(this, null);
                Type propType = property.GetType();
                dynamic defaultValue = GetDefaultValue(propType);
                if (attribute == null || (!attribute.AllowEdit && (!attribute.AllowInitialValue || item.Value != defaultValue)))
                {
                    property.SetValue(this, (object)item.Value, null);
                }
#else
                PropertyDescriptor property = TypeDescriptor.GetProperties(this)[item.Key];
                EditableAttribute attribute = property.Attributes.OfType<EditableAttribute>().SingleOrDefault();
                object propValue = property.GetValue(this);
                Type propType = property.PropertyType;
                dynamic defaultValue = GetDefaultValue(propType);
                if (attribute == null || (!attribute.AllowEdit && (!attribute.AllowInitialValue || item.Value != defaultValue)))
                {
                    property.SetValue(this, item.Value);
                }
#endif
            }
            this._backup = null;
            this.IsChanged = false;
        }

        /// <summary>
        /// Gets the object's changed status.
        /// </summary>
        [IgnoreDataMember]
        public bool IsChanged 
        { 
            get 
            { 
                return this._isChanged; 
            }
            protected set
            { 
                if (this._isChanged != value)
                {
                    this._isChanged = value;
                    RaisePropertyChanged("IsChanged");
                }
            }
        }
        #endregion
    }
}
